package gatperdut.chato.core.handler.entity;

import gatperdut.chato.core.ChatoServer;
import gatperdut.chato.core.characters.BaseController;
import gatperdut.chato.core.characters.BotController;
import gatperdut.chato.core.characters.health.HealthController;
import gatperdut.chato.core.entities.PlayerController;
import gatperdut.chato.core.handler.ChatoHandler;
import gatperdut.chato.core.interpreter.BaseInterpreter;
import gatperdut.chato.core.interpreter.BotInterpreter;
import gatperdut.chato.core.interpreter.PlayerInterpreter;
import gatperdut.chato.core.interpreter.login.PlayerLogin;
import gatperdut.chato.core.interpreter.mainmenu.PlayerMainMenu;
import gatperdut.chato.core.item.inventory.EntityInventoryController;
import gatperdut.chato.core.item.inventory.InventoryController;
import gatperdut.chato.core.scores.ScoresController;
import gatperdut.chato.core.skills.SkillsController;
import gatperdut.chato.core.threads.NotifyingThread;
import gatperdut.chato.model.Chato.Entity.NPC;
import gatperdut.chato.model.Chato.Player.Player;
import gatperdut.chato.model.Chato.Player.PlayerFactory;

import java.net.Socket;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class EntityHandler extends ChatoHandler {

    private final Set<Socket> connections = new HashSet<Socket>();

    private final Set<Player> loggedPlayers = new HashSet<Player>();

    private final Map<Socket, PlayerController> socketToController = new HashMap<Socket, PlayerController>();

    private final Map<NPC, BotController> npcToController = new HashMap<NPC, BotController>();

    private final List<Player> registeredPlayers;

    private int playersInGame = 0;

    public EntityHandler( ChatoServer chatoServer ) {
        super( chatoServer );
        registeredPlayers = getChatoServer().getDatasource().getChato().getPlayerContainer().getPlayers();
    }

    private void addRegisteredPlayer( Player player ) {
        getRegisteredPlayers().add( player );
    }

    public boolean isUsernameRegistered( String username ) {
        List<Player> players = getRegisteredPlayers();
        for ( Player p : players ) {
            if ( p.getUsername().equals( username ) ) {
                return true;
            }
        }

        return false;
    }

    public void logInPlayer( Player player ) {
        getLoggedPlayers().add( player );
    }

    public void logOutPlayer( Player player ) {
        if ( player != null ) {
            getLoggedPlayers().remove( player );
            getChatoServer().getLogger().info( "Player " + player.getUsername() + " has logged out." );
        }
    }

    public boolean isPlayerLoggedIn( String username ) {
        for ( Player p : getLoggedPlayers() ) {
            if ( p.getUsername().equals( username ) ) {
                return true;
            }
        }

        return false;
    }

    public boolean playerExists( String username, String password ) {
        List<Player> players = getRegisteredPlayers();
        for ( Player p : players ) {
            if ( p.getUsername().equals( username ) && p.getPassword().equals( password ) ) {
                return true;
            }
        }

        return false;
    }

    public Player addPlayerAccount( String username, String password ) {
        Player player = PlayerFactory.eINSTANCE.createPlayer();
        player.setUsername( username );
        player.setPassword( password );
        addRegisteredPlayer( player );
        getChatoServer().getDatasource().save();
        return player;
    }

    public Player retrievePlayer( String username ) {
        List<Player> players = getRegisteredPlayers();
        for ( Player p : players ) {
            if ( p.getUsername().equals( username ) ) {
                return p;
            }
        }

        return null;
    }

    public BaseController createPlayerController( Socket newClientSocket ) {
        BaseController playerController;
        BaseInterpreter playerInterpreter;
        PlayerLogin playerLogin;
        PlayerMainMenu playerMainMenu;

        playerController = new PlayerController( getChatoServer(), newClientSocket );
        // --interpreter&login&mainmenu
        playerInterpreter = new PlayerInterpreter( (PlayerController) playerController );
        playerLogin = new PlayerLogin( (PlayerInterpreter) playerInterpreter );
        ( (PlayerInterpreter) playerInterpreter ).setPlayerLogin( playerLogin );
        playerMainMenu = new PlayerMainMenu( (PlayerInterpreter) playerInterpreter );
        ( (PlayerInterpreter) playerInterpreter ).setPlayerMainMenu( playerMainMenu );
        playerController.setInterpreter( playerInterpreter );
        // --echoes
        playerController.getEchoes().setBaseController( playerController );
        // --combat
        playerController.getCombatController().setBaseController( playerController );
        addConnection( newClientSocket, (PlayerController) playerController );
        ( (NotifyingThread) playerController ).addListener( getChatoServer() );

        return playerController;
    }

    public void loadBots() {
        BotController botController;
        BaseInterpreter botInterpreter;
        InventoryController ic;
        ScoresController sc;
        HealthController hc;
        SkillsController skc;
        for ( NPC npc : getChatoServer().getDatasource().getChato().getBotContainer().getBots() ) {
            botController = new BotController( getChatoServer(), npc );
            botController.getEchoes().setBaseController( botController );
            // --inventory
            ic = new EntityInventoryController( getChatoServer(), npc.getInventory(), botController );
            botController.setInventoryController( ic );
            // --scores
            sc = new ScoresController( npc.getScores() );
            botController.setScoresController( sc );
            // --health
            hc = new HealthController( npc.getHealth() );
            botController.setHealthController( hc );
            // --skills
            skc = new SkillsController( npc.getSkillsContainer() );
            botController.setSkillsController( skc );
            // --interpreter
            botInterpreter = new BotInterpreter( botController );
            botController.setInterpreter( botInterpreter );
            // --combat
            botController.getCombatController().setBaseController( botController );
            addNpc( npc, botController );
            botController.start();
        }

    }

    public void removeConnection( Socket socket ) {
        getConnections().remove( socket );
        getSocketToController().remove( socket );
    }

    public void addConnection( Socket socket, PlayerController playerController ) {
        getConnections().add( socket );
        getSocketToController().put( socket, playerController );
    }

    public void addNpc( NPC npc, BotController botController ) {
        getNpcToController().put( npc, botController );
    }

    public void removeNpc( NPC npc ) {
        getNpcToController().remove( npc );
    }

    public Set<Socket> getConnections() {
        return connections;
    }

    public Set<Player> getLoggedPlayers() {
        return loggedPlayers;
    }

    public Map<Socket, PlayerController> getSocketToController() {
        return socketToController;
    }

    public Map<NPC, BotController> getNpcToController() {
        return npcToController;
    }

    public int getPlayersInGame() {
        return playersInGame;
    }

    public void addPlayerInGame() {
        playersInGame++;
    }

    public void removePlayerInGame() {
        playersInGame--;
    }

    public List<Player> getRegisteredPlayers() {
        return registeredPlayers;
    }

}
